-- return {
--    "neovim/nvim-lspconfig",
--    event = { "BufReadPre", "BufNewFile" },
-- }
return {
  "mason-org/mason-lspconfig.nvim",
  opts = {},
  dependencies = {
    {
      "mason-org/mason.nvim",
      opts = {
        install_root_dir = vim.fn.stdpath "data" .. "/mason",
        registries = {
          "github:mason-org/mason-registry",
        },
        log_level = vim.log.levels.INFO,
        ui = {
          border = "rounded",
          icons = {
            package_installed = "✓",
            package_pending = "➜",
            package_uninstalled = "✗",
          },
        },
        keymaps = {
          -- Keymap to expand a package
          toggle_package_expand = "<CR>",
          -- Keymap to install the package under the current cursor position
          install_package = "i",
          -- Keymap to reinstall/update the package under the current cursor position
          update_package = "u",
          -- Keymap to check for new version for the package under the current cursor position
          check_package_version = "c",
          -- Keymap to update all installed packages
          update_all_packages = "U",
          -- Keymap to check which installed packages are outdated
          check_outdated_packages = "C",
          -- Keymap to uninstall a package
          uninstall_package = "X",
          -- Keymap to cancel a package installation
          cancel_installation = "<C-c>",
          -- Keymap to apply language filter
          apply_language_filter = "<C-f>",
          -- Keymap to toggle viewing package installation log
          toggle_package_install_log = "<CR>",
          -- Keymap to toggle the help view
          toggle_help = "g?",
        },
      },
    },

    -- LSP
    "neovim/nvim-lspconfig",
    -- 增强lua 的开发体验
    "folke/neodev.nvim", -- lua
    -- Lsp 的相关插件加载的工作进度
    "j-hui/fidget.nvim",
  },
  config = function()
    -- neodev 与 fidget 必须在 lsp 配置服务之前设置
    -- lua 全局变量的识别,比如 vim
    require("neodev").setup {
      library = {
        plugins = { "nvim-dap-ui" },
        types = true,
      },
    }
    -- fidget 必须在 lsp 配置服务之前设置
    require("fidget").setup {}

    local sign_define_diagnstic = function(err, warn, hint, info)
      local x = vim.diagnostic.severity
      vim.diagnostic.config {
        virtual_text = {
          -- source = "always",  -- Or "if_many"
          prefix = "■-> ", -- Could be '●', '■', '▎', 'x'
        },
        virtual_lines = false, --  多行诊断信息, 可以不设置, 使用插件trouble.nvim 在 buffer 中显示更加友好
        signs = {
          text = {
            [x.ERROR] = err or "✘",
            [x.WARN] = warn or "",
            [x.HINT] = hint or "⚑",
            [x.INFO] = info or "",
          },
        },
        underline = true,
        severity_sort = true,
        update_in_insert = true,
        float = {
          source = true, -- Or "if_many"
        },
      }
    end
    local icon = {
      ERROR = "", -- "✘",
      WARN = "", --"",
      HINT = "⚑", -- '󰌵',
      INFO = "", -- "", -- '󰋇',
    }

    sign_define_diagnstic(icon.ERROR, icon.WARN, icon.HINT, icon.INFO)

    --#region servers installed
    -- fomat, lint servers
    -- 注意：区分 lsp 的服务， 和对应的语言代码格式化或代码检测服务的安装方式不一样
    local mason_registry = require "mason-registry"
    local formatSevers = function(servers)
      for _, name in pairs(servers) do
        local success, package = pcall(mason_registry.get_package, name)
        if success and not package:is_installed() then
          vim.notify("[mason-registry] '" .. name .. "' installing...")
          package:install()
        end
      end
    end
    mason_registry.refresh(vim.schedule_wrap(function()
      formatSevers {
        "stylua", -- lua formatter
        "luacheck",
        -- "biome", -- 速度比 prettier 快的格式化工具
        "prettier",  -- prettier formatter
        "prettierd", -- js
        "isort",     -- python formatter
        "black",     -- python formatter
        "pylint",    -- python linter
        "mypy",      -- python
        "ruff",      -- python
        "eslint_d",  -- js linter
        -- "pyright",

        "codespell",

        "codelldb",
        "clang-format", -- c/c++
        "gofumpt",      -- go
        "goimports",    -- go
        "jq",           -- json
        "shfmt",        -- sh

        -- rustup component add rustfmt
        -- "rustfmt", -- deprecated: rustfmt should now be installed via rustup

        "markdownlint", -- markdown
        -- "actionlint", -- yaml
      }
    end))

    -- LSP 服务
    local lsp_servers = {
      -- LSP 服务
      "lua_ls",
      "rust_analyzer",
      "pyright",
      "jsonls",
      "ts_ls",
      "html",
      "emmet_ls",
      "cssls",
      "tailwindcss",
      "vue_ls",
      "svelte",
      "bashls",
      "yamlls",
      "prismals",
      "gopls",
      "graphql",
    }
    require("mason-lspconfig").setup {
      automatic_enable = true,
      -- https://github.com/mason-org/mason-lspconfig.nvim
      -- https://mason-registry.dev/registry/list
      -- 使用服务器别名
      ensure_installed = lsp_servers,
    }
    --#endregion


    ----------------------------------------------------------------
    --[[ local opts = {
      ensure_installed = {
        "lua-language-server"
      }
    }
    require("mason").setup(opts)
    local function ensure_installed()
      for _, tool in ipairs(opts.ensure_installed) do
        local p = require("mason-registry").get_package(tool)
        if not p:is_installed() then
          p:install()
        end
      end
    end
    if require("mason-registry").refresh then
      require("mason-registry").refresh(ensure_installed)
    else
      ensure_installed()
    end ]]
    ----------------------------------------------------------------



    --#region setup servers
    -- 参考: http://blog.gitcode.com/de72d1116c77f948b6c1a661fcbecc60.html
    -- https://gitcode.com/gh_mirrors/nv/nvim-lspconfig/blob/master/doc/configs.md#gopls

    local capabilities = require("cmp_nvim_lsp").default_capabilities()
    -- :help lsp-config
    -- :help lspconfig-all
    vim.lsp.config("lua_ls", {
      cmd = { "lua-language-server" },
      filetypes = { "lua" },
      capabilities = capabilities,
      -- settings. See `:help lsp-quickstart`
      settings = {
        Lua = {
          diagnostics = {
            -- lua 中全局的 vim 变量不报警告
            globals = { "vim" },
          },
        },
      },
    })
    vim.lsp.enable "lua_ls"

    vim.lsp.config("rust_analyzer", {
      -- https://www.andersevenrud.net/neovim.github.io/lsp/configurations/rust_analyzer/
      cmd = { "rust-analyzer" },
      filetypes = { "rust" },
      capabilities = capabilities,
      settings = {
        ["rust-analyzer"] = {
          diagnostic = { enable = true },
          checkOnSave = {
            command = "check", -- clippy / check
          },
          inlayHints = {
            enable = true,
          },
        },
      },
    })
    vim.lsp.enable "rust_analyzer"

    vim.lsp.config("yamlls", {})
    vim.lsp.enable "yamlls"

    vim.lsp.config("gopls", {
      capabilities = capabilities,
      cmd = { "gopls" },
      filetypes = { "go", "gomod", "gowork", "gotmpl" },
      settings = {
        gopls = {
          analyses = {
            unusedparams = true,
          },
          staticcheck = true,
          gofumpt = true,
        },
      },
    })
    vim.lsp.enable "gopls"

    vim.lsp.config("clangd", require("lspconfig.configs.clangd").default_config)
    vim.lsp.enable "clangd"

    --#endregion

    --#region lsp attach
    local lspFormat = function(buf)
      local lspFmt = function()
        -- vim.lsp.buf.format { async = true, bufnr = vim.api.nvim_get_current_buf() }
        -- vim.lsp.buf.format { async = true, bufnr = buf }
        vim.lsp.buf.format { async = true }
        -- Workaround for diagnostics disappearing when formatting with no changes
        -- https://github.com/neovim/neovim/issues/25014
        vim.diagnostic.enable()
      end
      -- 保存格式化
      vim.api.nvim_create_autocmd("BufWritePre", {
        group = vim.api.nvim_create_augroup("LspFormatting", { clear = true }),
        buffer = buf,
        -- buffer = vim.api.nvim_get_current_buf(),
        callback = function()
          lspFmt()
        end,
      })
      -- 快捷键格式化
      vim.keymap.set("n", "<leader>fl", lspFmt, { buffer = buf, desc = "LSP: [F]ormat code" })
    end
    local conformFormat = function(buf)
      local conformFmt = function()
        require("conform").format {
          timeout_ms = 500,
          lsp_format = "fallback",
        }
      end
      -- 保存格式化
      vim.api.nvim_create_autocmd("BufWritePre", {
        group = vim.api.nvim_create_augroup("ConformFormatting", { clear = true }),
        buffer = buf,
        callback = function()
          -- 可以在 conform.nvim 插件中配置 format_on_save 选项自动格式化
          conformFmt()
        end,
      })
      -- 快捷键格式化
      vim.keymap.set({ "n", "v" }, "<leader>fc", conformFmt, { buffer = buf, desc = "conform.nvim: [F]ormat code" })
    end

    local formatter = function(client, buf)
      -- 这样就禁止了 lsp 服务的格式操作
      -- client.server_capabilities.documentFormattingProvider = false
      -- client.server_capabilities.documentRangeFormattingProvider = false
      if client.supports_method "textDocument/formatting" then
        -- 调用 Lsp 格式化
        lspFormat(buf)
        -- vim.notify "lsp formatter"
      else
        -- 调用插件conform.nvim格式化
        conformFormat(buf)
        -- vim.notify "conform.nvim formatter"
      end
    end
    local toggle_inlay_hint = function(client, buf)
      if vim.lsp.inlay_hint and client.server_capabilities.inlayHintProvider then
        vim.keymap.set("n", "<Space>ht", function()
          vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
          vim.lsp.inlay_hint.enable(vim.lsp.inlay_hint.is_enabled(), { bufnr = buf })
        end, { desc = "Toggle Inlay Hints." })
      else
        vim.notify "Not supported inlay hint"
      end
    end

    local hover_highlight_word = function(client, buf)
      -- https://neovim.io/doc/user/lsp.html
      -- vim.notify(client.name, vim.log.levels.INFO, {})
      if client.server_capabilities.documentHighlightProvider then
        -- 光标所在的字符词语高亮相同的单词， 可以用插件： "RRethy/vim-illuminate",
        -- vim.api.nvim_exec(
        --   [[
        --     augroup lsp_document_highlight
        --       autocmd! * <buffer>
        --       autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
        --       autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()
        --     augroup END
        --   ]],
        --   false
        -- )
        vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
          buffer = buf,
          callback = vim.lsp.buf.document_highlight,
        })
        vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, {
          buffer = buf,
          callback = vim.lsp.buf.clear_references,
        })
      end
    end

    local on_attach = function(buf)
      vim.api.nvim_buf_set_option(buf, "omnifunc", "v:lua.vim.lsp.omnifunc")
      local nmap = function(keys, func, desc)
        -- See `:help vim.lsp.*` for documentation on any of the below functions
        if desc then
          desc = "LSP: " .. desc
        end
        vim.keymap.set("n", keys, func, {
          buffer = buf,
          desc = desc,
          noremap = true,
          silent = true,
        })
      end

      -- 跳转到引用位置
      -- nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences")
      nmap("gr", vim.lsp.buf.references, "[G]oto [R]eferences")
      nmap("gi", vim.lsp.buf.implementation, "[G]oto [I]mplementation")
      nmap("gK", vim.lsp.buf.hover, "[H]over [D]ocumentation")
      nmap("gD", vim.lsp.buf.definition, "[G]oto [D]efinition")
      nmap("gf", vim.lsp.buf.type_definition, "Type [D]efinition")
      nmap("gd", vim.lsp.buf.declaration, "[G]oto [D]eclaration")
      nmap("<leader>ca", vim.lsp.buf.code_action, "Selects a code action")
    end

    vim.api.nvim_create_autocmd("LspAttach", {
      group = vim.api.nvim_create_augroup("UserLspConfig", {}),
      callback = function(ev)
        -- 获取服务信息
        local client = vim.lsp.get_client_by_id(ev.data.client_id)
        if client == nil then
          return
        end

        -- 是否显示 inlay hint
        toggle_inlay_hint(client, ev.buf)
        --  格式化设置
        formatter(client, ev.buf)
        -- 高亮鼠标悬浮的所以词
        hover_highlight_word(client, ev.buf)

        on_attach(ev.buf)

        vim.lsp.completion.enable(true, ev.data.client_id, ev.buf, { autotrigger = false })
      end,
    })
    --#endregion
  end,
}
